home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / bc-1_02.lha / bc-1.02 / util.c < prev    next >
C/C++ Source or Header  |  1992-03-04  |  16KB  |  795 lines

  1. /* util.c: Utility routines for bc. */
  2.  
  3. /*  This file is part of bc written for MINIX.
  4.     Copyright (C) 1991, 1992 Free Software Foundation, Inc.
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License , or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; see the file COPYING.  If not, write to
  18.     the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.     You may contact the author by:
  21.        e-mail:  phil@cs.wwu.edu
  22.       us-mail:  Philip A. Nelson
  23.                 Computer Science Department, 9062
  24.                 Western Washington University
  25.                 Bellingham, WA 98226-9062
  26.        
  27. *************************************************************************/
  28.  
  29.  
  30. #include "bcdefs.h"
  31. #ifndef VARARGS
  32. #include <stdarg.h>
  33. #else
  34. #include <varargs.h>
  35. #endif
  36. #include "global.h"
  37. #include "proto.h"
  38.  
  39.  
  40. /* strcopyof mallocs new memory and copies a string to to the new
  41.    memory. */
  42.  
  43. char *
  44. strcopyof (str)
  45.      char *str;
  46. {
  47.   char *temp;
  48.  
  49.   temp = (char *) bc_malloc (strlen (str)+1);
  50.   return (strcpy (temp,str));
  51. }
  52.  
  53.  
  54. /* nextarg adds another value to the list of arguments. */
  55.  
  56. arg_list *
  57. nextarg (args, val)
  58.      arg_list *args;
  59.      char val;
  60. { arg_list *temp;
  61.  
  62.   temp = (arg_list *) bc_malloc (sizeof (arg_list));
  63.   temp->av_name = val;
  64.   temp->next = args;
  65.  
  66.   return (temp);
  67. }
  68.  
  69.  
  70. /* For generate, we must produce a string in the form
  71.     "val,val,...,val".  We also need a couple of static variables
  72.    for retaining old generated strings.  It also uses a recursive
  73.    function that builds the string. */
  74.  
  75. static char *arglist1 = NULL, *arglist2 = NULL;
  76.  
  77.  
  78. /* make_arg_str does the actual construction of the argument string.
  79.    ARGS is the pointer to the list and LEN is the maximum number of
  80.    characters needed.  1 char is the minimum needed. COMMAS tells
  81.    if each number should be seperated by commas.*/
  82.  
  83. _PROTOTYPE (static char *make_arg_str, (arg_list *args, int len, int commas));
  84.  
  85. static char *
  86. make_arg_str (args, len, commas)
  87.       arg_list *args;
  88.       int len;
  89.       int commas;
  90. {
  91.   char *temp;
  92.   char sval[20];
  93.  
  94.   /* Recursive call. */
  95.   if (args != NULL)
  96.     temp = make_arg_str (args->next, len+11, commas);
  97.   else
  98.     {
  99.       temp = (char *) bc_malloc (len);
  100.       *temp = 0;
  101.       return temp;
  102.     }
  103.  
  104.   /* Add the current number to the end of the string. */
  105.   if (len != 1 && commas) 
  106.     sprintf (sval, "%d,", args->av_name);
  107.   else
  108.     sprintf (sval, "%d", args->av_name);
  109.   temp = strcat (temp, sval);
  110.   return (temp);
  111. }
  112.  
  113. char *
  114. arg_str (args, commas)
  115.      arg_list *args;
  116.      int commas;
  117. {
  118.   if (arglist2 != NULL) 
  119.     free (arglist2);
  120.   arglist2 = arglist1;
  121.   arglist1 = make_arg_str (args, 1, commas);
  122.   return (arglist1);
  123. }
  124.  
  125.  
  126. /* free_args frees an argument list ARGS. */
  127.  
  128. void
  129. free_args (args)
  130.       arg_list *args;
  131.   arg_list *temp;
  132.  
  133.   temp = args;
  134.   while (temp != NULL)
  135.     {
  136.       args = args->next;
  137.       free (temp);
  138.       temp = args;
  139.     }
  140. }
  141.  
  142.  
  143. /* Check for valid parameter (PARAMS) and auto (AUTOS) lists.
  144.    There must be no duplicates any where.  Also, this is where
  145.    warnings are generated for array parameters. */
  146.  
  147. void
  148. check_params ( params, autos )
  149.      arg_list *params, *autos;
  150. {
  151.   arg_list *tmp1, *tmp2;
  152.  
  153.   /* Check for duplicate parameters. */
  154.   if (params != NULL)
  155.     {
  156.       tmp1 = params;
  157.       while (tmp1 != NULL)
  158.     {
  159.       tmp2 = tmp1->next;
  160.       while (tmp2 != NULL)
  161.         {
  162.           if (tmp2->av_name == tmp1->av_name) 
  163.         yyerror ("duplicate parameter names");
  164.           tmp2 = tmp2->next;
  165.         }
  166.       if (tmp1->av_name < 0)
  167.         warn ("Array parameter");
  168.       tmp1 = tmp1->next;
  169.     }
  170.     }
  171.  
  172.   /* Check for duplicate autos. */
  173.   if (autos != NULL)
  174.     {
  175.       tmp1 = autos;
  176.       while (tmp1 != NULL)
  177.     {
  178.       tmp2 = tmp1->next;
  179.       while (tmp2 != NULL)
  180.         {
  181.           if (tmp2->av_name == tmp1->av_name) 
  182.         yyerror ("duplicate auto variable names");
  183.           tmp2 = tmp2->next;
  184.         }
  185.       tmp1 = tmp1->next;
  186.     }
  187.     }
  188.  
  189.   /* Check for duplicate between parameters and autos. */
  190.   if ((params != NULL) && (autos != NULL))
  191.     {
  192.       tmp1 = params;
  193.       while (tmp1 != NULL)
  194.     {
  195.       tmp2 = autos;
  196.       while (tmp2 != NULL)
  197.         {
  198.           if (tmp2->av_name == tmp1->av_name) 
  199.         yyerror ("variable in both parameter and auto lists");
  200.           tmp2 = tmp2->next;
  201.         }
  202.       tmp1 = tmp1->next;
  203.     }
  204.     }
  205. }
  206.  
  207.  
  208. /* Initialize the code generator the parser. */
  209.  
  210. void
  211. init_gen ()
  212. {
  213.   /* Get things ready. */
  214.   break_label = 0;
  215.   continue_label = 0;
  216.   next_label  = 1;
  217.   out_count = 2;
  218.   if (compile_only) 
  219.     printf ("@i");
  220.   else
  221.     init_load ();
  222.   had_error = FALSE;
  223.   did_gen = FALSE;
  224. }
  225.  
  226.  
  227. /* generate code STR for the machine. */
  228.  
  229. void
  230. generate (str)
  231.       char *str;
  232. {
  233.   did_gen = TRUE;
  234.   if (compile_only)
  235.     {
  236.       printf ("%s",str);
  237.       out_count += strlen(str);
  238.       if (out_count > 60)
  239.     {
  240.       printf ("\n");
  241.       out_count = 0;
  242.     }
  243.     }
  244.   else
  245.     load_code (str);
  246. }
  247.  
  248.  
  249. /* Execute the current code as loaded. */
  250.  
  251. void
  252. run_code()
  253. {
  254.   /* If no compile errors run the current code. */
  255.   if (!had_error && did_gen)
  256.     {
  257.       if (compile_only)
  258.     {
  259.       printf ("@r\n"); 
  260.       out_count = 0;
  261.     }
  262.       else
  263.     execute ();
  264.     }
  265.  
  266.   /* Reinitialize the code generation and machine. */
  267.   if (did_gen)
  268.     init_gen();
  269.   else
  270.     had_error = FALSE;
  271. }
  272.  
  273.  
  274. /* Output routines: Write a character CH to the standard output.
  275.    It keeps track of the number of characters output and may
  276.    break the output with a "\<cr>". */
  277.  
  278. void
  279. out_char (ch)
  280.      char ch;
  281. {
  282.   if (ch == '\n')
  283.     {
  284.       out_col = 0;
  285.       putchar ('\n');
  286.     }
  287.   else
  288.     {
  289.       out_col++;
  290.       if (out_col == 70)
  291.     {
  292.       putchar ('\\');
  293.       putchar ('\n');
  294.       out_col = 1;
  295.     }
  296.       putchar (ch);
  297.     }
  298. }
  299.  
  300.  
  301. /* The following are "Symbol Table" routines for the parser. */
  302.  
  303. /*  find_id returns a pointer to node in TREE that has the correct
  304.     ID.  If there is no node in TREE with ID, NULL is returned. */
  305.  
  306. id_rec *
  307. find_id (tree, id)
  308.      id_rec *tree;
  309.      char   *id;
  310. {
  311.   int cmp_result;
  312.   
  313.   /* Check for an empty tree. */
  314.   if (tree == NULL)
  315.     return NULL;
  316.  
  317.   /* Recursively search the tree. */
  318.   cmp_result = strcmp (id, tree->id);
  319.   if (cmp_result == 0)
  320.     return tree;  /* This is the item. */
  321.   else if (cmp_result < 0)
  322.     return find_id (tree->left, id);
  323.   else
  324.     return find_id (tree->right, id);  
  325. }
  326.  
  327.  
  328. /* insert_id_rec inserts a NEW_ID rec into the tree whose ROOT is
  329.    provided.  insert_id_rec returns TRUE if the tree height from
  330.    ROOT down is increased otherwise it returns FALSE.  This is a
  331.    recursive balanced binary tree insertion algorithm. */
  332.  
  333. int insert_id_rec (root, new_id)
  334.      id_rec **root;
  335.      id_rec *new_id;
  336. {
  337.   id_rec *A, *B;
  338.  
  339.   /* If root is NULL, this where it is to be inserted. */
  340.   if (*root == NULL)
  341.     {
  342.       *root = new_id;
  343.       new_id->left = NULL;
  344.       new_id->right = NULL;
  345.       new_id->balance = 0;
  346.       return (TRUE);
  347.     }
  348.  
  349.   /* We need to search for a leaf. */
  350.   if (strcmp (new_id->id, (*root)->id) < 0)
  351.     {
  352.       /* Insert it on the left. */
  353.       if (insert_id_rec (&((*root)->left), new_id))
  354.     {
  355.       /* The height increased. */
  356.       (*root)->balance --;
  357.       
  358.       switch ((*root)->balance)
  359.     {
  360.     case  0:  /* no height increase. */
  361.       return (FALSE);
  362.     case -1:  /* height increase. */
  363.       return (FALSE);
  364.     case -2:  /* we need to do a rebalancing act. */
  365.       A = *root;
  366.       B = (*root)->left;
  367.       if (B->balance <= 0)
  368.         {
  369.           /* Single Rotate. */
  370.           A->left = B->right;
  371.           B->right = A;
  372.           *root = B;
  373.           A->balance = 0;
  374.           B->balance = 0;
  375.         }
  376.       else
  377.         {
  378.           /* Double Rotate. */
  379.           *root = B->right;
  380.           B->right = (*root)->left;
  381.           A->left = (*root)->right;
  382.           (*root)->left = B;
  383.           (*root)->right = A;
  384.           switch ((*root)->balance)
  385.         {
  386.         case -1:
  387.           A->balance = 1;
  388.           B->balance = 0;
  389.           break;
  390.         case  0:
  391.           A->balance = 0;
  392.           B->balance = 0;
  393.           break;
  394.         case  1:
  395.           A->balance = 0;
  396.           B->balance = -1;
  397.           break;
  398.         }
  399.           (*root)->balance = 0;
  400.         }
  401.     }     
  402.     } 
  403.     }
  404.   else
  405.     {
  406.       /* Insert it on the right. */
  407.       if (insert_id_rec (&((*root)->right), new_id))
  408.     {
  409.       /* The height increased. */
  410.       (*root)->balance ++;
  411.       switch ((*root)->balance)
  412.         {
  413.         case 0:  /* no height increase. */
  414.           return (FALSE);
  415.         case 1:  /* height increase. */
  416.           return (FALSE);
  417.         case 2:  /* we need to do a rebalancing act. */
  418.           A = *root;
  419.           B = (*root)->right;
  420.           if (B->balance >= 0)
  421.         {
  422.           /* Single Rotate. */
  423.           A->right = B->left;
  424.           B->left = A;
  425.           *root = B;
  426.           A->balance = 0;
  427.           B->balance = 0;
  428.         }
  429.           else
  430.         {
  431.           /* Double Rotate. */
  432.           *root = B->left;
  433.           B->left = (*root)->right;
  434.           A->right = (*root)->left;
  435.           (*root)->left = A;
  436.           (*root)->right = B;
  437.           switch ((*root)->balance)
  438.             {
  439.             case -1:
  440.               A->balance = 0;
  441.               B->balance = 1;
  442.               break;
  443.             case  0:
  444.               A->balance = 0;
  445.               B->balance = 0;
  446.               break;
  447.             case  1:
  448.               A->balance = -1;
  449.               B->balance = 0;
  450.               break;
  451.             }
  452.           (*root)->balance = 0;
  453.         }
  454.         }     
  455.     } 
  456.     }
  457.   
  458.   /* If we fall through to here, the tree did not grow in height. */
  459.   return (FALSE);
  460. }
  461.  
  462.  
  463. /* Initialize variables for the symbol table tree. */
  464.  
  465. void
  466. init_tree()
  467. {
  468.   name_tree  = NULL;
  469.   next_array = 1;
  470.   next_func  = 1;
  471.   next_var   = 4;  /* 0 => ibase, 1 => obase, 2 => scale, 3 => last. */
  472. }
  473.  
  474.  
  475. /* Lookup routines for symbol table names. */
  476.  
  477. int
  478. lookup (name, namekind)
  479.      char *name;
  480.      int  namekind;
  481. {
  482.   id_rec *id;
  483.  
  484.   /* Warn about non-standard name. */
  485.   if (strlen(name) != 1)
  486.     warn ("multiple letter name - %s", name);
  487.  
  488.   /* Look for the id. */
  489.   id = find_id (name_tree, name);
  490.   if (id == NULL)
  491.     {
  492.       /* We need to make a new item. */
  493.       id = (id_rec *) bc_malloc (sizeof (id_rec));
  494.       id->id = strcopyof (name);
  495.       id->a_name = 0;
  496.       id->f_name = 0;
  497.       id->v_name = 0;
  498.       insert_id_rec (&name_tree, id);
  499.     }
  500.  
  501.   /* Return the correct value. */
  502.   switch (namekind)
  503.     {
  504.       
  505.     case ARRAY:
  506.       /* ARRAY variable numbers are returned as negative numbers. */
  507.       if (id->a_name != 0)
  508.     {
  509.       free (name);
  510.       return (-id->a_name);
  511.     }
  512.       id->a_name = next_array++;
  513.       a_names[id->a_name] = name;
  514.       if (id->a_name < MAX_STORE)
  515.     {
  516.       if (id->a_name >= a_count)
  517.         more_arrays ();
  518.       return (-id->a_name);
  519.     }
  520.       yyerror ("Too many array variables");
  521.       exit (1);
  522.  
  523.     case FUNCT:
  524.       if (id->f_name != 0)
  525.     {
  526.       free(name);
  527.       return (id->f_name);
  528.     }
  529.       id->f_name = next_func++;
  530.       f_names[id->f_name] = name;
  531.       if (id->f_name < MAX_STORE)
  532.     {
  533.       if (id->f_name >= f_count)
  534.         more_functions ();
  535.       return (id->f_name);
  536.     }
  537.       yyerror ("Too many functions");
  538.       exit (1);
  539.  
  540.     case SIMPLE:
  541.       if (id->v_name != 0)
  542.     {
  543.       free(name);
  544.       return (id->v_name);
  545.     }
  546.       id->v_name = next_var++;
  547.       v_names[id->v_name - 1] = name;
  548.       if (id->v_name <= MAX_STORE)
  549.     {
  550.       if (id->v_name >= v_count)
  551.         more_variables ();
  552.       return (id->v_name);
  553.     }
  554.       yyerror ("Too many variables");
  555.       exit (1);
  556.     }
  557. }
  558.  
  559.  
  560. /* Print the welcome banner. */
  561.  
  562. void 
  563. welcome()
  564. {
  565.   printf ("This is free software with ABSOLUTELY NO WARRANTY.\n");
  566.   printf ("For details type `warranty'. \n");
  567. }
  568.  
  569.  
  570. /* Print out the warranty information. */
  571.  
  572. void 
  573. warranty(prefix)
  574.      char *prefix;
  575. {
  576.   printf ("\n%s%s\n\n", prefix, BC_VERSION);
  577.   printf ("%s%s%s%s%s%s%s%s%s%s%s",
  578. "    This program is free software; you can redistribute it and/or modify\n",
  579. "    it under the terms of the GNU General Public License as published by\n",
  580. "    the Free Software Foundation; either version 2 of the License , or\n",
  581. "    (at your option) any later version.\n\n",
  582. "    This program is distributed in the hope that it will be useful,\n",
  583. "    but WITHOUT ANY WARRANTY; without even the implied warranty of\n",
  584. "    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n",
  585. "    GNU General Public License for more details.\n\n",
  586. "    You should have received a copy of the GNU General Public License\n",
  587. "    along with this program. If not, write to the Free Software\n",
  588. "    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.\n\n");
  589. }
  590.  
  591. /* Print out the limits of this program. */
  592.  
  593. void
  594. limits()
  595. {
  596.   printf ("BC_BASE_MAX     = %d\n",  BC_BASE_MAX);
  597.   printf ("BC_DIM_MAX      = %ld\n", (long) BC_DIM_MAX);
  598.   printf ("BC_SCALE_MAX    = %d\n",  BC_SCALE_MAX);
  599.   printf ("BC_STRING_MAX   = %d\n",  BC_STRING_MAX);
  600.   printf ("MAX Exponent    = %ld\n", (long) LONG_MAX);
  601.   printf ("MAX code        = %ld\n", (long) BC_MAX_SEGS * (long) BC_SEG_SIZE);
  602.   printf ("multiply digits = %ld\n", (long) LONG_MAX / (long) 90);
  603.   printf ("Number of vars  = %ld\n", (long) MAX_STORE);
  604. #ifdef OLD_EQ_OP
  605.   printf ("Old assignment operatiors are valid. (=-, =+, ...)\n");
  606. #endif 
  607. }
  608.  
  609. /* bc_malloc will check the return value so all other places do not
  610.    have to do it!  SIZE is the number of types to allocate. */
  611.  
  612. char *
  613. bc_malloc (size)
  614.      int size;
  615. {
  616.   char *ptr;
  617.  
  618.   ptr = (char *) malloc (size);
  619.   if (ptr == NULL)
  620.     out_of_memory ();
  621.  
  622.   return ptr;
  623. }
  624.  
  625.  
  626. /* The following routines are error routines for various problems. */
  627.  
  628. /* Malloc could not get enought memory. */
  629.  
  630. void
  631. out_of_memory()
  632. {
  633.   fprintf (stderr, "Fatal error: Out of memory for malloc.\n");
  634.   exit (1);
  635. }
  636.  
  637.  
  638.  
  639. /* The standard yyerror routine.  Built with variable number of argumnets. */
  640.  
  641. #ifndef VARARGS
  642. #ifdef __STDC__
  643. void
  644. yyerror (char *str, ...)
  645. #else
  646. void
  647. yyerror (str)
  648.      char *str;
  649. #endif
  650. #else
  651. void
  652. yyerror (str, va_alist)
  653.      char *str;
  654. #endif
  655. {
  656.   char *name;
  657.   va_list args;
  658.  
  659. #ifndef VARARGS   
  660.    va_start (args, str);
  661. #else
  662.    va_start (args);
  663. #endif
  664.   if (is_std_in)
  665.     name = "(standard_in)";
  666.   else
  667.     name = g_argv[optind-1];
  668.   fprintf (stderr,"%s %d: ",name,line_no);
  669.   vfprintf (stderr, str, args);
  670.   fprintf (stderr, "\n");
  671.   had_error = TRUE;
  672.   va_end (args);
  673. }
  674.  
  675.  
  676. /* The routine to produce warnings about non-standard features
  677.    found during parsing. */
  678.  
  679. #ifndef VARARGS
  680. #ifdef __STDC__
  681. void 
  682. warn (char *mesg, ...)
  683. #else
  684. void
  685. warn (mesg)
  686.      char *mesg;
  687. #endif
  688. #else
  689. void
  690. warn (mesg, va_alist)
  691.      char *mesg;
  692. #endif
  693. {
  694.   char *name;
  695.   va_list args;
  696.  
  697. #ifndef VARARGS   
  698.   va_start (args, mesg);
  699. #else
  700.   va_start (args);
  701. #endif
  702.   if (std_only)
  703.     {
  704.       if (is_std_in)
  705.     name = "(standard_in)";
  706.       else
  707.     name = g_argv[optind-1];
  708.       fprintf (stderr,"%s %d: ",name,line_no);
  709.       vfprintf (stderr, mesg, args);
  710.       fprintf (stderr, "\n");
  711.       had_error = TRUE;
  712.     }
  713.   else
  714.     if (warn_not_std)
  715.       {
  716.     if (is_std_in)
  717.       name = "(standard_in)";
  718.     else
  719.       name = g_argv[optind-1];
  720.     fprintf (stderr,"%s %d: (Warning) ",name,line_no);
  721.     vfprintf (stderr, mesg, args);
  722.     fprintf (stderr, "\n");
  723.       }
  724.   va_end (args);
  725. }
  726.  
  727. /* Runtime error will  print a message and stop the machine. */
  728.  
  729. #ifndef VARARGS
  730. #ifdef __STDC__
  731. void
  732. rt_error (char *mesg, ...)
  733. #else
  734. void
  735. rt_error (mesg)
  736.      char *mesg;
  737. #endif
  738. #else
  739. void
  740. rt_error (mesg, va_alist)
  741.      char *mesg;
  742. #endif
  743. {
  744.   va_list args;
  745.   char error_mesg [255];
  746.  
  747. #ifndef VARARGS   
  748.   va_start (args, mesg);
  749. #else
  750.   va_start (args);
  751. #endif
  752.   vsprintf (error_mesg, mesg, args);
  753.   va_end (args);
  754.   
  755.   fprintf (stderr, "Runtime error (func=%s, adr=%d): %s\n",
  756.        f_names[pc.pc_func], pc.pc_addr, error_mesg);
  757.   runtime_error = TRUE;
  758. }
  759.  
  760.  
  761. /* A runtime warning tells of some action taken by the processor that
  762.    may change the program execution but was not enough of a problem
  763.    to stop the execution. */
  764.  
  765. #ifndef VARARGS
  766. #ifdef __STDC__
  767. void
  768. rt_warn (char *mesg, ...)
  769. #else
  770. void
  771. rt_warn (mesg)
  772.      char *mesg;
  773. #endif
  774. #else
  775. void
  776. rt_warn (mesg, va_alist)
  777.      char *mesg;
  778. #endif
  779. {
  780.   va_list args;
  781.   char error_mesg [255];
  782.  
  783. #ifndef VARARGS   
  784.   va_start (args, mesg);
  785. #else
  786.   va_start (args);
  787. #endif
  788.   vsprintf (error_mesg, mesg, args);
  789.   va_end (args);
  790.  
  791.   fprintf (stderr, "Runtime warning (func=%s, adr=%d): %s\n",
  792.        f_names[pc.pc_func], pc.pc_addr, error_mesg);
  793. }
  794.